/**
 * 深拷贝: 通常可以通过 JSON.parse(JSON.stringify(object)) 来解决
 */

let a = {
    age: 1,
    jobs: {
        first: 'FE'
    }
}
let b = JSON.parse(JSON.stringify(a))

a.jobs.first = 'native'

console.log(b.jobs.first); // FE

/**
 * 这个方法也是有局限性的:
 * 会忽略 undefined
 * 会忽略 symbol
 * 不能序列化函数
 * 不能解决循环引用的对象
 */

let obj = {
    a: 1,
    b: {
        c: 2,
        d: 3
    }
}
obj.c = obj.b
obj.e = obj.a
obj.b.c = obj.c
obj.b.d = obj.b
obj.b.e = obj.b.c

// TypeError: Converting circular structure to JSON
let newObj = JSON.parse(JSON.stringify(obj))

console.log(newObj)

// 如果你有这么一个循环引用对象，你会发现你不能通过该方法深拷贝

// 在遇到函数、undefined 或 symbol 的时候，该对象也不能正常的序列化
let a = {
    age: undefined,
    sex: Symbol('male'),
    jobs: function () {},
    name: 'xxx'
}

let b = JSON.parse(JSON.stringify(a))

console.log(b); // {name: "xxx"}

// 但是在通常情况下，复杂数据都是可以序列化的，所以这个函数可以解决大部分问题，并且该函数是内置函数中处理深拷贝性能最快的。
// 当然如果你的数据中含有以上三种情况下，可以使用 lodash 的深拷贝函数。

// 如果你所需拷贝的对象含有内置类型并且不包含函数，可以使用 MessageChannel

function structuralClone (obj) {
    return new Promise (resolve => {
        const {port1, port2} = new MessageChannel()
        port2.onmessage = ev => resolve(ev.data)
        port1.postMessage(obj)
    })
}

var obj = {
    a: 1,
    b: {
        c: b
    }
}
// 注意该方法是异步的
// 可以处理 undefined 和 循环引用对象
(async () => {
    const clone = await structuralClone(obj)
})()